﻿#include "arduino_parser.h"

#include <assert.h>
#include <string>
#include <set>
#include <map>
#include <list>
#include <memory>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include <codecvt>
using namespace std;

#include "JsonHelper.h"  

enum
{
	arduino_type_null,
	arduino_type_macros,
	arduino_type_comment,
	arduino_type_variant,
	arduino_type_function,
	arduino_type_class,
	arduino_type_enum,
	arduino_type_enum_value,
};

//对象前置声明
struct  arduino_object;
struct  arduino_comment;
struct  arduino_variant;
struct  arduino_function;
struct  arduino_class;
struct  arduino_enum;
struct  arduino_enum_value;
typedef shared_ptr<arduino_object> arduino_object_ptr;
typedef shared_ptr<arduino_comment> arduino_comment_ptr;
typedef shared_ptr<arduino_variant> arduino_variant_ptr;
typedef shared_ptr<arduino_function> arduino_function_ptr;
typedef shared_ptr<arduino_class> arduino_class_ptr;
typedef shared_ptr<arduino_enum> arduino_enum_ptr;
typedef shared_ptr<arduino_enum_value> arduino_enum_value_ptr;


struct arduino_object
{
	int type;
	int ppp = 0;// 0=public,1=private, 2=protected
	unsigned line = 0;

	arduino_object(int type = arduino_type_null) :type(type) {}
	virtual ~arduino_object() {}

	operator bool()
	{
		return type != arduino_type_null;
	}

	virtual string type_str()
	{
		if (type == arduino_type_macros)return "macros";
		else if (type == arduino_type_comment)return "comment";
		else if (type == arduino_type_variant)return "variant";
		else if (type == arduino_type_function)return "function";
		else if (type == arduino_type_class)return "class";
		else if (type == arduino_type_enum)return "enum";
		else if (type == arduino_type_enum_value)return "enum value";
		else return "nothing";
	}

	virtual string name_str()
	{
		return "";
	}

	virtual string argument_str(int idx)
	{
		return "";
	}
};

struct arduino_context;
typedef shared_ptr<arduino_context> arduino_context_ptr;
struct arduino_context
{
	arduino_context_ptr parent;
	multimap<string, shared_ptr<arduino_object>> objects;
	arduino_context(arduino_context_ptr parent = nullptr) :parent(parent) {}
};

struct arduino_comment : public arduino_object
{
	string content;
	arduino_comment(const string& content) :arduino_object(arduino_type_comment), content(content) {}
};

struct arduino_variant : public arduino_object
{
	bool isconst = false;
	bool isextern = false;
	bool isstatic = false;
	string reftype;// && & &*
				   //string type;
	string name;
	string default_value;
	vector<shared_ptr<arduino_variant>> argument;
	arduino_variant() :arduino_object(arduino_type_variant) {}

	string type_str()
	{
		return reftype;
	}

	string name_str()
	{
		return name;
	}

	string argument_str(int idx)
	{
		if (idx>=0 && idx<argument.size())
		{
			return argument[idx]->name_str();
		}
		return __super::argument_str(idx);
	}
};

struct arduino_function : public arduino_object
{
	bool isconst = false;
	bool isextern = false;
	bool isstatic = false;
	bool decl = false;
	vector<shared_ptr<arduino_variant>> argument;
	string return_value;
	arduino_function() :arduino_object(arduino_type_function) {}
	~arduino_function() {}
};

struct arduino_class : public arduino_object
{
	bool pre_declare = false;
	bool is_template = false;
	string name;
	string bases;
	list<string> friends;
	arduino_context_ptr context;
	multimap<string, shared_ptr<arduino_object>> objects;
	arduino_class() :arduino_object(arduino_type_class), context(new arduino_context()) {}
};

struct arduino_enum_value : public arduino_object
{
	string name;
	string value;
	arduino_enum_value() :arduino_object(arduino_type_enum_value) {}
};

struct arduino_enum : public arduino_object
{
	bool isclass = false;
	string name;
	string base;
	map<string, shared_ptr<arduino_enum_value>> members;
	arduino_enum() :arduino_object(arduino_type_enum) {}
};


class eof : public exception {};

struct reader
{
	ifstream file;
	char current = 0;
	bool end = false;
	reader()
	{
		
	}
	bool open(const string& filename)
	{
		file.open(filename, ifstream::in);
		if (!file)
			throw logic_error("file not found.");

		return read();
	}

	void close()
	{
		if (file)
			file.close();
		current = 0;
		end = false;
	}

	bool read()
	{
		if (end)
			throw eof();

		char ret;
		file.read(&ret, 1);
		if (!file)
			return false;
		current = ret;
		return true;
	}
	char operator++()
	{
		if (!read())
		{
			end = true;
			current = ' ';
		}
		return current;
	}
	operator char()
	{
		return current;
	}
};

//错误描述
map<string, vector<string>> arduino_errors = {
	{ "fmt",{ "%s line %u:", "%s 第%u行 : " } },
	{ "C1021",{ "invalid preprocessor command", "无法识别的预处理指令" } },
	{ "C2001",{ "newline in constant", "常量中有换行符" } },
	{ "C2015",{ "too many characters in constant", "字符常量中太多字符" } },
	{ "C2018",{ "unknown character ", "未知字符" } },
	{ "C2059",{ "syntax error", "语法错误" } },
	{ "C2143",{ "syntax error : missing ']' before ')'", "语法错误 : 在“)”前缺少“]”" } },
	{ "M1",{ "don't support default value", "不支持默认值" } }
};

struct arduino_context_state
{
	enum class arduino_domain { namespace_, global_, class_, method_, enum_, unin_, struct_, if_, while_, do_, for_, nothing_ }domain = arduino_domain::global_;
	enum class arduino_permission { public_, private_, protected_ }permission = arduino_permission::public_;
	enum class arduino_var_property { nothing_, static_ = 0b0001, const_ = 0b0010, extern_ = 0b0100 };
	int var_property = (int)arduino_var_property::nothing_;
};

const set<string> arduino_prekeys = {
	"include","pragma","define","ifdef","ifndef""elif","if","else","endif","undef","line","error"
};

const set<string> arduino_keywords = { "int","double","float","short","long",
"const","char","unsigned","class","struct","using","public",
"private","protected","template","static","extern","sizeof",
"new","delete","void","namespace","return","if","while",
"do","for","case","switch","break","continue","goto","operator",
"auto" };

class arduino_parser
{
	bool isobject(const string & str)
	{
		if (keyblocks.find(str) != keyblocks.end())
		{
			return true;
		}
		if (keyservers.find(str) != keyservers.end())
		{
			return true;
		}
		return false;
	}

	void insert(string name, arduino_object_ptr obj, int ppp)
	{
		obj->ppp = ppp;
		obj->line = line;
		validate_varname(name);
		context->objects.insert(make_pair(name, obj));
	}
	operator char() { return iter; }
	void error(const char* str, const char* arg = nullptr)
	{
		string out(100, 0);
		sprintf(&out[0], arduino_errors["fmt"][0].c_str(), str, line);
		out = out.c_str();
		if (arduino_errors.find(str) == arduino_errors.end())
			throw logic_error(str);
		throw logic_error(out + arduino_errors[str][0] + (arg ? arg : ""));
	}
	char operator++()
	{
		++iter;
		return iter;
	}
	void push(arduino_context_ptr value)
	{
		value->parent = context;
		context = value;
	}
	void pop()
	{
		context = context->parent;
	}
	string readto_nextline(bool to = true)
	{
		stringstream ss;
		do
		{
			if (iter.end)
				break;
			if (iter == '\n')
				break;
			if (iter != '\r')
				ss << iter;
			++iter;
		} while (1);
		if(to)
			next();
		return ss.str();
	}
	void backslash()
	{
		if (iter == '/')
		{
			++iter;
			if (iter == '/')
			{
				++iter;
				//insert("//", arduino_comment_ptr(new arduino_comment(readto_nextline())), 0);
				readto_commentend(false);
			}
			else if (iter == '*')
			{
				++iter;
				readto_commentend(true);
			}
			else
				next();
		}
	}
	int next()
	{
		int count = 0;
		while (1)
		{
			if (iter.end)return 0;
			if (iter < 0)break;
			if (iter == '/')backslash();
			if (iter == '\n') { ++line; ++iter; continue; }
			if (!isblank(iter) && isprint(iter))break;
			++iter;
			++count;
		}
		return 1;
	}
	string readto_nextword(bool to = true)
	{
		next();
		stringstream ss;
		while (1) {
			if ('_' == iter || '~' == iter || iter < 0) { ss << iter; ++iter; continue; }
			//if (':' == iter) { ++iter; if (iter != ':')error("syntax error，:: is namespace usage"); ss << "::"; ++iter; continue; }
			if (isblank(iter))break;
			if (ispunct(iter))break;
			if (!isprint(iter))break;
			ss << iter;
			++iter;
		}
		auto word = ss.str();
		if (to)
			next();
		return word;
	}
	string get_char_literal()
	{
		stringstream ss;
		for (;;)
		{
			if (iter == '\\') { ++iter; if (iter == '\r') { ++iter; } if (iter == '\n') ++line; ++iter; continue; }
			else if (iter == '\'') { ++iter; break; }
			else if (iter == '\n') { line++; }
			ss << iter;
			++iter;
		}
		return ss.str();
	}
	string get_string_literal()
	{
		stringstream ss;
		for (;;)
		{
			if (iter == '\n') { error("C2001"); }
			if (iter == '\\') { ++iter; if (iter == '\r') { ++iter; } if (iter == '\n') ++line; ++iter; continue; }
			if (iter == '"') { ++iter; break; }
			ss << iter;
			++iter;
		}
		return ss.str();
	}
	string get_range(char ch)
	{
		if (!(ch == '}' || ch == ']' || ch == '>' || ch == ')'))throw;
		char beg = ch == ']' ? '[' : (ch == '}' ? '{' : (ch == ')' ? '(' : (ch == '>' ? '<' : '?')));
		stringstream ss;
		for (;;)
		{
			if (iter == beg) { ss << iter; ++iter; ss << get_range(ch); ss << ch; continue; }
			else if (iter == '\'') { ++iter; ss << get_char_literal(); continue; }
			else if (iter == '"') { ++iter; ss << get_string_literal(); continue; }
			else if (iter == '\n') { ++line; }
			else if (iter == '/') { backslash(); continue; }
			else if (iter == ch)
			{
				++iter; next();	break;
			}
			ss << iter;
			++iter;
		}
		return ss.str();
	}
	void readto_commentend(bool multiline, bool to = true)
	{
		stringstream ss;
		if (multiline)
		{
			do
			{
				if (iter == '*')
				{
					++iter;
					if (iter == '/')
					{
						++iter;
						break;
					}
					else
					{
						ss << '*';
					}
				}
				if (iter == '\r') { ++iter; continue; }
				if (iter == '\n') { ++line; ++iter; continue; }
				ss << iter;
				++iter;
			} while (1);
		}
		else
		{
			do
			{
				if (iter.end)
					break;
				if (iter == '\r') { ++iter; continue; }
				if (iter == '\n') { ++iter; break; }
				ss << iter;
				++iter;
			} while (1);
		}
		auto temp = arduino_comment_ptr(new arduino_comment(ss.str()));
		insert(multiline ? "/*...*/" : "//...", temp, 0);
		if(!multiline) ++line;
		if (to)
			next();
	}
	string readto(char ch)
	{
		stringstream ss;
		do
		{
			if (iter == ch)
			{
				++iter;
				next();
				break;
			}
			if (iter == '(') { ++iter; get_range(')'); continue; }
			if (iter == '{') { ++iter; get_range('}'); continue; }
			if (iter == '[') { ++iter; get_range(']'); continue; }
			if (iter == '<') { ++iter; get_range('>'); continue; }
			if (iter == '\r') { ++iter; continue; }
			if (iter == '\n') { ++line; }
			ss << iter;
			++iter;
		} while (1);
		return ss.str();
	}
	string readto(const string& match)
	{
		stringstream ss;
		do
		{
			if (match.find_first_of(iter) != string::npos)
			{
				break;
			}
			if (iter == '(') { ++iter; get_range(')'); continue; }
			if (iter == '{') { ++iter; get_range('}'); continue; }
			if (iter == '[') { ++iter; get_range(']'); continue; }
			if (iter == '<') { ++iter; get_range('>'); continue; }
			if (iter == '\r') { ++iter; continue; }
			if (iter == '\n') { ++line; }
			ss << iter;
			++iter;
		} while (1);
		return ss.str();
	}
	void precmd()
	{
		++iter;
		auto word = readto_nextword();
		if (arduino_prekeys.find(word) != arduino_prekeys.end())
		{
			readto_nextline();
		}
		else
			error("C1021");
	}
	void object_argument(vector<shared_ptr<arduino_variant>>& argument)
	{
		next();
		if (iter == ')') { ++iter; next(); return; }
		for (;;)
		{
			if (iter == '\'' || iter == '\"')
			{
				string reftype;
				string name;
				if (iter == '\'')
				{
					++iter;
					reftype = "char";
					name = get_char_literal();
					next();
				}
				else if (iter == '"')
				{
					++iter;
					reftype = "char[]";
					name = get_string_literal();
					next();
				}
				if (iter != ','&&iter != ')')
					error("C2018");
				arduino_variant_ptr temp(new arduino_variant);
				temp->reftype = reftype;
				temp->name = name;
				argument.push_back(temp);
				if (iter == ')') { ++iter; next(); return; }
				++iter; next();
			}
			else
			{
				for (;;)
				{
					if (iter == '&' || iter == '*') { ++iter; }
					auto seg = readto_nextword();
					if (seg.empty())
						error("C2059");
					if (iter >= 0)
					{
						if (iter == '(')
						{
							++iter;
							string name = get_range(')');
							if (iter != ','&&iter != ')')
								error("C2018");
							arduino_variant_ptr temp(new arduino_variant);
							temp->name = name;
							if (!temp->name.empty())validate_varname(temp->name);
							temp->reftype = seg;
							argument.push_back(temp);
							if (iter == ')') { ++iter; next(); return; }
							++iter;
							next();
							break;
						}
						else if (ispunct(iter))
						{
							if (iter != ','&&iter != ')')
								error("C2018");
							arduino_variant_ptr temp(new arduino_variant);
							temp->name = seg;
							if (!temp->name.empty())validate_varname(temp->name);
							temp->reftype = "";
							argument.push_back(temp);
							if (iter == ')') { ++iter; next(); return; }
							++iter;
							next();
							break;
						}
					}
				}
			}
		}
	}
	void function_argument(vector<shared_ptr<arduino_variant>>& argument)
	{
		next();
		if (iter == ')') { ++iter; next(); return; }
		for (;;)
		{
			if (iter == '\'' || iter == '\"')
			{
				string reftype;
				string name;
				if (iter == '\'')
				{
					++iter;
					reftype = "char";
					name = get_char_literal();
					next();
				}
				else if (iter == '"')
				{
					++iter;
					reftype = "char[]";
					name = get_string_literal();
					next();
				}
				if (iter != ','&&iter != ')')
					error("C2018");
				arduino_variant_ptr temp(new arduino_variant);
				temp->reftype = reftype;
				temp->name = name;
				argument.push_back(temp);
				if (iter == ')') { ++iter; next(); return; }
				++iter; next();
			}
			else
			{
				list<string> all;
				for (;;)
				{
					auto seg = readto_nextword();
					//if (seg.empty() && all.empty())
					//	error("C2059");
					if (iter >= 0 && ispunct(iter))
					{
						if (iter == '&' || iter == '*') 
						{ 
							all.push_back(seg);
							all.push_back(string(1, iter));
							++iter; 
							continue;
						}
						else if (iter == '[') 
						{ 
							++iter; 
							next(); 
							if (iter != ']')
								error("C2143"); 
							all.push_back("[]"); 
							++iter; 
						}
						else if (iter == '=')
							readto(",)");//error("M1");
						else if (iter == '<') 
						{ 
							++iter; 
							all.push_back("<" + get_range('>') + ">");
							continue; 
						}
						else if (iter == '(') 
						{ 
							++iter;
							all.push_back(seg);
							seg = get_range(')');
						}
						else if (iter != ','&&iter != ')')
							error("C2018");
						arduino_variant_ptr temp(new arduino_variant);
						temp->name = all.empty() ? "" : seg;
						if (!temp->name.empty())validate_varname(temp->name);
						temp->reftype = all.empty() ? seg : list2str(all);
						argument.push_back(temp);
						if (iter == ')') { ++iter; next(); return; }
						++iter;
						next();
						break;
					}
					all.push_back(seg);
				}
			}
		}
	}
	bool in(const string& char_list)
	{
		auto ch = (char)iter;
		for (auto item : char_list)
			if (item == ch)
				return true;
		return false;
	}
	void validate_varname(const string& word)
	{
		if (word.empty())
			error("C2059");
		if (arduino_keywords.find(word) != arduino_keywords.end())
			error("C2059");
		//if (word.find_first_of(':') != string::npos)
		//	error("C2059", ":");
	}
	string list2str(list<string> l) 
	{ 
		stringstream ss; 
		for (auto it = l.begin(); it!=l.end();)
		{
			ss << *it;
			++it;
			if (it==l.end())
			{
				break;
			}
			ss << " ";
		}
		return ss.str();
	}
	// domain, 0=global,1=class,2=struct,3=globalfunction,4=memberfunction,5=lambda,6=namespace,7=noname
	void block(int dm)
	{
		auto ppp = 0;// 0=public,1=private, 2=protected
		while (1)
		{
			if (next() == 0)return;
			if (iter == '#') { precmd(); continue; }
			if (iter == ';') { ++iter; continue; }
			if (dm != 0 && iter == '}') { ++iter; return; }
			list<string> types;
			while (1)
			{
				auto word = readto_nextword();
				if (word.empty())if (dm < 3)error("C2059"); else error("未实现执行代码的解析");
				if (dm == 1 || dm == 2)
				{
					if (word == "public") { ppp = 0; readto(':'); break; }
					else if (word == "private") { ppp = 1; readto(':'); break; }
					else if (word == "protected") { ppp = 2; readto(':'); break; }
				}
				if (word == "using" || word == "typedef")
				{
					readto(';');
					break;
				}
				else if (word == "class" || word == "struct")
				{
					auto tname = readto_nextword();
					if (iter == ':')
					{
						++iter;
						auto temp = arduino_class_ptr(new arduino_class());
						temp->bases = readto('{');
						temp->name = tname;
						insert(tname, arduino_object_ptr(temp), ppp);
						temp->pre_declare = true;
						push(temp->context);
						block(word == "class" ? 1 : 2);
						temp->pre_declare = false;
						pop();
					}
					else if (iter == ';') { ++iter; break; }
					else if (iter == '{')
					{
						++iter;
						auto temp = arduino_class_ptr(new arduino_class());
						temp->name = tname;
						insert(tname, arduino_object_ptr(temp), ppp);
						temp->pre_declare = true;
						push(temp->context);
						block(word == "class" ? 1 : 2);
						temp->pre_declare = false;
						pop();
					}
					word = "class " + tname;
					if (iter == ';') { ++iter; break; }
				}
				else if (word == "template")
				{
					if (iter != '<')error("C2059", string(1, iter).c_str());
					++iter;
					get_range('>');
					types.push_back("template<>");
					continue;
				}
				else if (word == "operator")
				{
					word = readto_nextword();
					if (word.empty())
					{
						if (iter == '(')
						{
							++iter;
							next();
							if (iter != ')')error("C2059", string(1, iter).c_str());
							++iter;
							next();
							if (iter != '(')error("C2059", string(1, iter).c_str());
							word = "operator()";
						}
						else
						{
							word = "operator" + readto("(");
						}
					}
					else
						word = "operator " + word;
				}
				else if (word == "enum")
				{
					auto enum_ = arduino_enum_ptr(new arduino_enum());
					auto name = readto_nextword();
					if (name == "class")
					{
						enum_->isclass = true;
						name = readto_nextword();
					}
					if (name.empty())
						enum_->name = "<unnamed_enum>";
					else
						enum_->name = name;
					if (iter == ':') { ++iter; enum_->base = readto('{'); }
					else if (iter != '{')error("C2059", string(1, iter).c_str());
					else ++iter;
					long long index = 0;
					while (1)
					{
						auto mname = readto_nextword();
						auto var = arduino_enum_value_ptr(new arduino_enum_value());
						if (iter == '=')
						{
							++iter;
							auto value = readto_nextword();
							if (value.empty())error("C2059", string(1, iter).c_str());
							index = atoi(value.c_str()) + 1;
							var->name = mname;
							var->value = value;
							if (!enum_->isclass)insert(mname, var, ppp);
							enum_->members[mname] = var;
							if (iter != ','&&iter != '}')error("C2059", string(1, iter).c_str());
							if (iter == '}') { ++iter; break; }
							++iter;
						}
						else if (iter == ',' || iter == '}')
						{
							var->name = mname;
							var->value = to_string(index++);
							if (!enum_->isclass)insert(mname, var, ppp);
							enum_->members[mname] = var;
							if (iter == '}') { ++iter; break; }
							++iter;
						}
						else
							error("C2059", string(1, iter).c_str());
					}
					insert(enum_->name, enum_, ppp);
					next();
					if (iter == ';') { ++iter; break; }
					continue;
				}
				else if (isobject(word))
				{
					types.push_back(word);
					do
					{
						auto obj = arduino_variant_ptr(new arduino_variant);
						auto name = readto_nextword();
						if (name.empty())
							obj->name = "<unnamed_variant>";
						else
							obj->name = name;
						++iter;
						object_argument(obj->argument);
						obj->reftype = list2str(types);
						insert(name, obj, ppp);
						if (iter == ';') { ++iter; break; }
						if (iter != ',') error("C2059");
						++iter;
					} while (1);
					break;
				}

				if (iter >= 0 && ispunct(iter))
				{
					if (iter == ',')
					{
						++iter;
						do
						{
						arduino_variant_ptr var(new arduino_variant);
						var->reftype = list2str(types);
						var->name = word;
						if (iter == '(')
						{
							++iter;
							object_argument(var->argument);
						}
						insert(word, var, ppp);
						/*while (1) {
							auto vname = readto_nextword();
							if (vname.empty())error("C2059");
							var->name = vname;
							insert(vname, var, ppp);
							if (iter == ';')break;
							if (iter != ',')error("C2059", string(1, iter).c_str());
							++iter;
						}*/
						if (iter == ';')break;
						if (iter == ',') ++iter;
						word = readto_nextword();
						} while (1);
						break;
					}
					if (iter == ':')
					{
						do {
							++iter; if (iter != ':')error("C2059", ":"); ++iter;
							auto next = readto_nextword(); if (next.empty())error("C2059", string(1, (char)iter).c_str());
							word += "::" + next;
						} while (iter == ':');
					}
					if (iter == '(')// function
					{
						++iter;
						arduino_function_ptr var(new arduino_function);
						insert(word, var, ppp);
						function_argument(var->argument);
						if (iter == ';')
							;
						else if (iter == ',')
							;
						else
							readto("{");
						if (iter == '{')
						{
							++iter; get_range('}');
						}
						else if (iter != ';' && iter != ',')
							error("C2059", string(1, iter).c_str());
						else
							var->decl = true;
						var->return_value = list2str(types);
						if (iter == ',')
						{
							++iter;
							continue;
						}
						break;
					}
					else if (iter == ';')
					{
						++iter;
						arduino_variant_ptr var(new arduino_variant);
						var->name = word;
						var->reftype = list2str(types);
						insert(word, var, ppp);
						types.clear();
						break;
					}
					else if (iter == '=')
					{
						++iter;
						arduino_variant_ptr var(new arduino_variant);
						var->reftype = list2str(types);
						var->name = word;
						var->default_value = readto(",;");
						insert(word, var, ppp);
						if (iter == ';') { ++iter; break; }
						continue;
					}
					else if (iter == '<')
					{
						++iter;
						types.push_back(word + "<" + get_range('>') + ">");
						continue;
					}
					else if (iter == '*' || iter == '&')
					{
						if (types.empty())
							error("C2059", string(1, iter).c_str());
						types.push_back(word);
						types.push_back(string(1, iter));
						++iter;
						continue;
					}
					else
					{
						//readto(';');
						//cout << "don't supported, ignore this line." << endl;
						//continue;
						error("C2059", string(1, iter).c_str());
					}
				}

				types.push_back(word);
			}
		}
	}
private:
	reader iter;
	set<string> keyblocks;
	set<string> keyservers;
	arduino_context_ptr context = shared_ptr<struct arduino_context>(new struct arduino_context());
	uint32_t line = 1;
	string result;
public:
	arduino_parser()
	{
		
	}

	bool parse(const string& srcFile, const string& boardFile)
	{
		string strBoard;

		iter.open(srcFile);

		ifstream in;
		in.open(boardFile, ifstream::in);
		if (in.is_open())
		{
			string str;
			string line;
			while (getline(in, line)) {
				str.append(line);
			}
			in.close();

			boost::property_tree::ptree doc;
			JsonHelper::parseFromString(str,doc);

			strBoard = doc.get<string>("model","");
			auto opt_block_list = doc.get_child_optional("block_list");
			if (opt_block_list) {
				const boost::property_tree::ptree & block_list = opt_block_list.get();
				BOOST_FOREACH(const boost::property_tree::ptree::value_type &v, block_list)
				{
					keyblocks.insert(v.second.get<string>("type"));
				}
			}
			auto opt_server_list = doc.get_child_optional("server_list");
			if (opt_server_list) {
				const boost::property_tree::ptree & server_list = opt_server_list.get();
				BOOST_FOREACH(const boost::property_tree::ptree::value_type &v, server_list)
				{
					keyservers.insert(v.second.get<string>("type"));
				}
			}
		}

		if (iter == (char)0xEF && ++iter == (char)0xBB && ++iter == (char)0xBF)++iter;// UTF-8
		else if (iter == (char)0xFF && ++iter == (char)0xFE && ++iter == (char)0x00 && ++iter == (char)0x00)++iter;// UTF-32, little endian
		else if (iter == (char)0x00 && ++iter == (char)0x00 && ++iter == (char)0xFE && ++iter == (char)0xFF)++iter;// UTF-32, bit endian
		else if (iter == (char)0xFF && ++iter == (char)0xFE)++iter;// UTF-16, little endian
		else if (iter == (char)0xFE && ++iter == (char)0xFF)++iter;// UTF-16, bit endian
		try { block(0); }
		catch (eof& e) 
		{
#ifdef _DEBUG
			cout << e.what() << endl;
#endif
		}


		boost::property_tree::ptree doc;
		doc.put("MainBoard", strBoard);

		set<string> blocks;
		boost::property_tree::ptree block_list;
		for (auto& obj : context->objects)
		{
			//shared_ptr<arduino_variant> spVar = dynamic_pointer_cast<arduino_variant>(obj.second);
			//assert(spVar);
			arduino_variant* pVar = dynamic_cast<arduino_variant*>(obj.second.get());
			if (pVar)
			{
				if (keyblocks.find(pVar->reftype) != keyblocks.end())
				{
					if (pVar->argument.size() < 2)
						continue;

					blocks.insert(pVar->name);

					arduino_variant* pVarModel = dynamic_cast<arduino_variant*>(pVar->argument[0].get());
					arduino_variant* pVarPort = dynamic_cast<arduino_variant*>(pVar->argument[1].get());
					//string name = obj.second->name_str();
					/*const char* GBK_LOCALE_NAME = ".936"; //GBK在windows下的locale name
					//构造GBK与wstring间的转码器（wstring_convert在析构时会负责销毁codecvt_byname，所以不用自己delete）
					wstring_convert<codecvt_byname<wchar_t, char, mbstate_t>> cv1(new codecvt_byname<wchar_t, char, mbstate_t>(GBK_LOCALE_NAME));
					wstring wtype = cv1.from_bytes(type);
					wstring_convert<codecvt_utf8<wchar_t>> cv2;
					string type = cv2.to_bytes(wtype);*/
					boost::property_tree::ptree item;
					//item.SetObject();
					item.put("type", pVar->reftype);
					item.put("model", pVarModel->name);
					item.put("port", pVarPort->name);
					item.put("name", pVar->name);
					block_list.push_back(make_pair("", item));
				}
			}
		}
		doc.put_child("Block", block_list);

		boost::property_tree::ptree server_list;
		for (auto& obj : context->objects)
		{
			arduino_variant* pVar = dynamic_cast<arduino_variant*>(obj.second.get());
			if (pVar)
			{
				if (keyservers.find(pVar->reftype) != keyservers.end())
				{
					//string name = obj.second->name_str();
					boost::property_tree::ptree item;
					item.put("type", pVar->reftype);
					item.put("name", pVar->name);
					boost::property_tree::ptree temp_block_list;
					for (auto& arg : pVar->argument)
					{
						arduino_variant* pVarArg = dynamic_cast<arduino_variant*>(arg.get());
						if (pVarArg)
						{
							if (blocks.find(pVarArg->name) != blocks.end())
							{
								boost::property_tree::ptree temp_block_item;
								temp_block_item.put_value(pVarArg->name);
								temp_block_list.push_back(make_pair("", temp_block_item));
							}
						}
					}
					item.put_child("block", temp_block_list);
					server_list.push_back(make_pair("", item));
				}
			}
		}
		doc.put_child("Server", server_list);

		JsonHelper::parseFromObject(doc, result);
		
		return true;
	}

	auto get_root()
	{
		return context;
	}

	const string & get_result() {
		return result;
	}
};

bool arduino_parse(const string& srcFile, const string& boardFile, string& jsonOut)
{
	arduino_parser parser;
	if (parser.parse(srcFile, boardFile)) {
#ifdef _DEBUG
		auto root = parser.get_root();
		cout << "total " << root->objects.size() << " objects." << endl;
		for (auto& obj : root->objects)
		{
			cout << obj.first << " line:" << obj.second->line << " type:" << obj.second->type_str() << endl;
}
#endif//
		jsonOut = parser.get_result();
		return true;
	}
	return false;
}